package com.sig.util;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 算数工具
 *
 * @author sig
 * @since 2019/1/26
 */
public final class MathUtil {

    private MathUtil() {
    }

    /**
     * 根据权重获取随机key
     *
     * @param weights
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> K randomKey(final Map<K, V> weights) {
        try {
            double sumWeight = .0D;
            for (V value : weights.values())
                sumWeight += Double.parseDouble(String.valueOf(value));
            return randomKey(weights, sumWeight);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据权重获取随机key
     *
     * @param weights
     * @param min 去掉比这个小的数(不包含自己)
     * @param <K>
     * @param <V>
     * @return
     */
    public static <K, V> K randomKey(final Map<K, V> weights, final K min) {
        Map<K, V> map = new HashMap<>(weights);
        try {
            double sumWeight = .0D;
            for (Iterator<Map.Entry<K, V>> iterator = map.entrySet().iterator(); iterator.hasNext(); ) {
                Map.Entry<K, V> entry = iterator.next();
                if (Double.compare(Double.parseDouble(String.valueOf(entry.getKey())), Double.parseDouble(String.valueOf(min))) == -1) {
                    iterator.remove();
                    continue;
                }
                sumWeight += Double.parseDouble(String.valueOf(entry.getValue()));
            }
            K randomKey = randomKey(weights, sumWeight);
            map.clear();
            map = null;
            return randomKey;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static <K, V> K randomKey(final Map<K, V> weights, final double sumWeight) {
        if (weights == null || weights.isEmpty())
            return null;
        int result = -1;
        double random = ThreadLocalRandom.current().nextDouble();
        double d1 = .0D;
        double d2 = .0D;
        List<K> list = new ArrayList<>(weights.keySet());
        for (int index = 0, size = list.size(); index < size; index++) {
            if (index > 0)
                d1 += Double.parseDouble(String.valueOf(weights.get(list.get(index - 1)))) / sumWeight;
            d2 += Double.parseDouble(String.valueOf(weights.get(list.get(index)))) / sumWeight;
            if (random >= d1 && random <= d2) {
                result = index;
                break;
            }
        }
        K key = list.get(result);
        list.clear();
        list = null;
        return key;
    }

    /**
     * 计算是否触发
     *
     * @param weight
     * @return
     */
    public static boolean trigger(final double weight) {
        double sumWeight = 1.0D;
        double d1 = .0D;
        double d2 = weight / sumWeight;
        double random = ThreadLocalRandom.current().nextDouble();
        return random >= d1 && random <= d2;
    }
}
